package com.coolingme.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import com.coolingme.domain.entity.MenuBack;
import com.coolingme.domain.entity.SecurityUser;
import com.coolingme.domain.entity.User;
import com.coolingme.domain.entity.UserInfo;
import com.coolingme.domain.vo.PageInfoVo;
import com.coolingme.domain.vo.UserVo;
import com.coolingme.mapper.RoleMapper;
import com.coolingme.mapper.UserInfoMapper;
import com.coolingme.mapper.UserMapper;
import com.coolingme.server.RedisServer;
import com.coolingme.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

	@Autowired
	private UserMapper userMapper;

	@Autowired
	private UserInfoMapper userInfoMapper;

	@Autowired
	private RoleMapper roleMapper;

	@Autowired
    RedisServer redisServer;

	@Override
	public Set<String> getRoles(SecurityUser securityUser) {
		// 用户名
		String userName = securityUser.getUserName();
		// 获取用户保存角色集合的key
		String redisRoleKey = User.getRedisRoleKey(userName);
		// 角色集合,是以key为“securityUser:userName”的Set类型数据
		Set<String> roles = new HashSet<String>();
		// 若redis存在当前key
		if (redisServer.hasKey(redisRoleKey)) {
			// 从redis中获取集合
			roles = redisServer.sGetString(redisRoleKey);
		} else {
			// redis不存在角色key，从mysql读取，并放在redis中,设置为1小时
			roles = roleMapper.listRoleKeyByUserId(securityUser.getId());
			long result = redisServer.sSetBySet(redisRoleKey, roles, 60 * 60 * 1);
			log.debug("{} 成功存放了 {} 个角色", redisRoleKey, result);
		}
		return roles;
	}

	@Override
	public Set<String> getPermissionURIs(Set<String> roles) {
		// 将Set类型的用户角色转为List
		List<String> roleList = new ArrayList<>(roles);

		// 获取用户的请求路径集合：用户所拥有的系统接口路径集合
		Set<String> urls = new HashSet<String>();

		// 每一个role的permisson都会在redis中存储，key为 roleKey(如 ROLE_ADMIN)
		switch (roles.size()) {
		case 0: // 用户没有角色
			urls = null;
			break;
		case 1: // 用户只有一个角色
			urls = redisServer.sGetString(roleList.get(0));
			break;
		case 2: // 用户有两个角色
			urls = redisServer.sUnionString(roleList.get(0), roleList.get(1));
			break;
		default: // 超过两个角色
			String firstRoleKey = roleList.get(0);// 获取第一个role
			Set<String> otherRoleKeys = roles;
			otherRoleKeys.remove(firstRoleKey);// 从集合中删除第一个role
			urls = redisServer.sUnionString(firstRoleKey, otherRoleKeys);
			break;
		}
		return urls;
	}

	@Override
	public Set<String> getPermissionURIs(Set<String> roles, String refererUri) {
		// 根据角色key和页面路径获取所有权限key
		Set<String> permissionsKeys = new HashSet<>();
		roles.forEach(roleKey -> {
			String permissionsKey = MenuBack.getRedisPermissionsKey(roleKey, refererUri);
			permissionsKeys.add(permissionsKey);
		});

		// 获取用户的请求路径集合：用户所拥有的系统接口路径集合
		Set<String> urls = new HashSet<>();

		// 每个角色对应的 页面 的 请求权限 都会在redis中存储
		switch (permissionsKeys.size()) {
		case 0: // 没有权限key
			urls = null;
			break;
		case 1: // 只有一个权限key
			urls = redisServer.sGetString(permissionsKeys.iterator().next());
			break;
		default: // 权限key数量大于或等于两个
			String firstPermissionsKey = permissionsKeys.iterator().next();
			Set<String> otherPermissionsKeys = permissionsKeys;
			otherPermissionsKeys.remove(firstPermissionsKey);// 从集合中删除第一个role
			urls = redisServer.sUnionString(firstPermissionsKey, otherPermissionsKeys);
			break;
		}
		return urls;
	}

	@Override
	public PageInfoVo<UserVo> selectPageInfo(String userName, Integer pageNum, Integer pageSize) {
		PageHelper.startPage(pageNum, pageSize);
		List<UserVo> userRoleVoList = userMapper.listUser(userName);
		PageInfo<UserVo> pageInfo = new PageInfo<>(userRoleVoList);
		return new PageInfoVo<>(pageInfo);
	}

	@Transactional
	@Override
	public void insert(User user) {
		userMapper.insert(user);
		userInfoMapper.insert(new UserInfo(user.getId()));
	}

}
